//! 自动生成Self::orm_get_with_pk、Self::orm_delete_with_pk、self.orm_delete,Self::orm_exist_with_pk,self.orm_exist方法

use proc_macro2::TokenStream as TokenStream2;
use quote::quote;

use super::struct_field_parse::{FieldConvertType, TinyOrmField, TinyOrmFieldData};

/// 结构体join相关汇总信息
#[derive(Clone, Debug)]
pub(crate) struct TinyOrmPkSumInfo {
    /// where by pk字段的sql
    pub(crate) pk_where_sql: String,
    /// 生成的相关方法
    pub(crate) token:TokenStream2,
    /// self主键相关token
    pub(crate) pk_self_fields:Vec<TokenStream2>
}

/// 实现主键相关方法
///
/// 必须设置主键信息
///
/// # 参数说明:
/// * table_name 对应数据库表名称
///
/// # 返回说明
/// (主键sql where 语句，生成的主键相关方法)
pub(super) fn impl_struct_orm_pk(
    orm_field_list: &[TinyOrmFieldData],
    table_name: &str,
) -> TinyOrmPkSumInfo {
    
    let pk_fields = orm_field_list.iter().filter_map(|orm_field_data| {
        if let TinyOrmFieldData::Pk(pk_field) = orm_field_data {
            Some(pk_field)
        } else {
            None
        }
    }).collect::<Vec<_>>();
    if pk_fields.is_empty() {
        panic!("impl_struct_orm_pk:未设置主键");
    }

    // 根据主键信息生成orm_get_by_pk,orm_update等相关方法
    // 生成主键查询和更新的where语句
    let pk_where_sql = pk_fields.iter()
        .map(|field| format!("{table_name}.{} = ?", field.field_db_name))
        .collect::<Vec<_>>()
        .join(" AND ");
    let pk_field_idents = pk_fields.iter().map(|field| field.field_ident.clone()).collect::<Vec<_>>();
    let pk_field_types = pk_fields.iter().map(|field| field.field_type.clone()).collect::<Vec<_>>();
    let pk_self_fields = pk_fields.iter()
        .map(
            |TinyOrmField {
                 field_type_convert_type,
                 field_ident,
                 ..
             }| match field_type_convert_type {
                FieldConvertType::Option => quote! { self.#field_ident.unwrap() },
                FieldConvertType::String => quote! { &self.#field_ident },
                FieldConvertType::None => quote! { self.#field_ident },
            },
        )
        .collect::<Vec<_>>();

    // 生成orm_get_by_pk 方法
    let code = quote! {
        /// orm_pk自动实现:通过主键获取记录
        pub async fn orm_get_with_pk(pool: &TinyOrmDbPool,#(#pk_field_idents: #pk_field_types),* ) -> AnyhowResult<Self>{
            let sql = Self::DB_META.build_select_sql(Self::DB_META.pk_where_sql);
            let query = Self::db_query(&sql)
                #(.bind(#pk_field_idents))*;
            Self::db_fetch_one(pool, query, Self::orm_row_map).await
                .with_context(|| "根据主键获取记录出错!")
        }
        /// orm_pk自动实现:通过主键删除记录
        pub async fn orm_delete_with_pk(pool: &TinyOrmDbPool,#(#pk_field_idents: #pk_field_types),* ) -> AnyhowResult<()>{
            let sql = Self::DB_META.build_delete_sql(Self::DB_META.pk_where_sql);
            let query = Self::db_query(&sql)
                #(.bind(#pk_field_idents))*;
            Self::db_execute(pool, query).await
                .with_context(|| "根据主键删除记录出错!")?;
            Ok(())
        }
        /// orm_pk自动实现:通过主键删除当前记录
        /// 实际调用Self::orm_delete_by_pk
        pub async fn orm_delete(&self,pool: &TinyOrmDbPool) -> AnyhowResult<()>{
            Self::orm_delete_with_pk(pool,#(#pk_self_fields),*).await
        }
        /// orm_pk自动实现:通过主键查询记录是否存在
        pub async fn orm_exist_with_pk(pool: &TinyOrmDbPool,#(#pk_field_idents: #pk_field_types),* ) -> AnyhowResult<bool>{
            let sql = Self::DB_META.build_exist_sql(Self::DB_META.pk_where_sql);
            let row: (i64,) = query_as(&sql)
                #(.bind(#pk_field_idents))*
                .fetch_one(pool)
                .await
                .with_context(|| "通过主键查询记录是否存在时出错!")?;
            Ok(row.0 > 0)
        }
        /// orm_pk自动实现:通过主键查询当前记录是否存在
        /// 实际调用Self::orm_exist_with_pk
        pub async fn orm_exist(&self,pool: &TinyOrmDbPool) -> AnyhowResult<bool>{
            Self::orm_exist_with_pk(pool,#(#pk_self_fields),*).await
        }
    };

    // @todo 同步实现orm_update等自定义方法
    TinyOrmPkSumInfo{
        pk_where_sql,
        token:code,
        pk_self_fields
    }
}
